from django.db import models
import os
import time
from django.conf import settings
# Create your models here.


class Permission(models.Model):
    """
    角色权限表暂时不动
    """
    pass



class Email(models.Model):
    """
    邮箱
    """
    # user=models.ManyToManyField(User,verbose_name="关联用户")
    email_address = models.EmailField(verbose_name="邮箱地址",null=True)
    #在admin中方便显示
    def __str__(self):
        return self.email_address

    class Meta:
        verbose_name="邮箱池"
        verbose_name_plural="邮箱池"

# class Progress(models.Model):
#     """
#     进度条相关事项
#     """
#     #格式化进度条显示
#     formatname_progress=models.FloatField(default=float(0), null=True,verbose_name="进度条事项")
#
#     def __str__(self):
#         return self.formatname_progress
#
#
#     def set_progress_value(self,type_progress,value):
#         type_progress=value
#         self.save()
#
#     @staticmethod
#     def get_progress_value(type_progress):
#         return type_progress
#
#     def init_progress_value(self,type_progress):
#         type_progress=float(0)
#         self.save()
#
#
#     class Meta:
#         verbose_name_plural="进度条"
#         verbose_name="进度条"

class User(models.Model):
    """
    登录状态由session记录不用在model内再设置变量
    """
    name=models.CharField(max_length=48,unique=True,verbose_name="用户名")
    password=models.CharField(max_length=256,verbose_name="密码")
    create_time = models.DateTimeField(auto_now_add=True,verbose_name="创建时间")
    user_role = models.ForeignKey(null=True,to="Role",verbose_name="职位",on_delete=models.CASCADE)
    email_data = models.ManyToManyField(Email, verbose_name="关联邮箱")
    email_condition = models.BooleanField(verbose_name="邮箱开关",default=False)
    progress=models.FloatField(default=float(0), null=True, verbose_name="进度条事项")

    # authority_level=models.IntegerField(default=1)
    # authority_level=models.ForeignKey()

    def __str__(self):
        return self.name

    ######
    #进度条相关操作
    #######
    def init_progress_bar_value(self):
        self.progress=float(0)
        self.save()

    def set_progress_bar_value(self,value):
        self.progress=value
        self.save()

    def get_progress_bar_value(self):
        return self.progress



    class Meta:
        ordering=["-create_time"]
        verbose_name="用户创建与查看"
        verbose_name_plural="用户创建与查看"

# class Email_User_ship(models.Model):



class Role(models.Model):
    """
    通过角色来划分权限
    """
    role=[('1','外来人员'),('2','员工'),('3','管理')]
    position=models.CharField(max_length=48,choices=role,default="员工",verbose_name="身份")
    # permission  todo:外键指向permission
    def __str__(self):
        return self.role[int(self.position)-1][1]
    class Meta:
        verbose_name="用户权限（不用）"
        verbose_name_plural = "用户权限（不用）"


class Email_group(models.Model):
    """
    用于划分邮件组
    """
    name=models.CharField(max_length=100,verbose_name="小组名",null=False,default="默认")
    email_data=models.ManyToManyField(Email,verbose_name="邮箱组内邮箱")

    def __str__(self):
        return self.name
    class Meta:
        verbose_name_plural="划分邮箱组"
        verbose_name="划分邮箱组"

class Compile(models.Model):
    """
    编译相关路径
    """
    compile_script_path=models.CharField(max_length=100,verbose_name="编译脚本运行路径")


    def __str__(self):
        return self.compile_script_path

    def get_script_path_exclude_file(self):
        """
        获取文件路径（不包含文件）
        :return:
        """
        folder_path,file_name=os.path.split(self.compile_script_path)
        return folder_path
    class Meta:
        verbose_name="编译脚本相关路径"
        verbose_name_plural="编译脚本相关路径"



class App(models.Model):
    """
    记录改变APP信息
    app_condition:当前app是否在使用状态
    """
    name=models.CharField(max_length=100,verbose_name="app中文名字",null=False)
    app_english_name=models.CharField(max_length=100,verbose_name="app英文名",null=False,default="none")
    short_name=models.CharField(max_length=100,verbose_name="app缩略名（用于格式化）",null=False,default="none")
    app_path=models.CharField(max_length=1000,verbose_name="app路径")
    #compiling running free
    app_condition=models.CharField(max_length=100,verbose_name="使用状态（编译、run、空闲）",null=False,default="free")
    app_compile_num=models.CharField(max_length=1000,verbose_name="编译号",null=False,default="0")
    app_script=models.ForeignKey(Compile,verbose_name="编译脚本路径",on_delete=models.SET_NULL,null=True)
    app_compile_time=models.CharField(max_length=100,verbose_name="上次编译时间",null=False,default="none")

    def __str__(self):
        return self.name

    def set_condition_free(self):
        self.app_condition="free"
        self.save()

    def set_condition_run(self):
        self.app_condition = "running"
        self.save()

    def set_condition_compile(self):
        self.app_condition = "compiling"
        self.save()

    def set_compile_time(self):
        self.app_compile_time=time.strftime('%Y年%m月%d日%H时%M分')
        self.save()

    def judge_condition_free(self):
        if self.app_condition=="free":
            return True
        else:
            return False

    def judge_condition_compile(self):
        if self.app_condition=="compiling":
            return True
        else:
            return False

    def judge_condition_run(self):
        if self.app_condition == "running":
            return True
        else:
            return False
    #获得脚本shell命令
    def get_shell_compile_command(self):
        return self.app_script.compile_script_path+" "+self.app_compile_num

    # def get_shell_
    class Meta:
        verbose_name="App"
        verbose_name_plural="App"



"""  文件管理模型"""
# 直接获取原绝对路径
def get_media_abspath():
    #  所有文件都直接放到 media 目录下

    return os.path.join(settings.MEDIA_ROOT,"File_manage")


class Directory(models.Model):
    """
        name: 用户能看到的文件目录名. todo: 同级目录下不允许重复
        parent: 上级目录，如果本身是根目录则 parent 为空字符
        path: 用户能看到的相对路径，需要用 get_full_path 才能转换成绝对路径
        owner: 属于哪一个用户id
        share: 共享文件夹 1为共享  0为不共享
        判断逻辑：先判断share是否为共享再判断从属id
        搜索逻辑：显示数据库中所有相关联
    """
    name = models.CharField(max_length=256)  # 如 / home
    owner = models.ForeignKey(User, on_delete=models.CASCADE)
    # share = models.IntegerField()  #1为共享  0为不共享
    parent = models.ForeignKey('Directory', null=True, on_delete=models.CASCADE)  # 只有根目录没有 parent   没有则为空null
    path = models.CharField(max_length=4096, default='')  #path不包含主目录名

    def __str__(self):
        return self.name or '/'

    @classmethod  # 无需实例化直接启动 cls为
    def create_root_dir(cls, user):
        """
            用户注册时，会同时创建一个根目录对象
        """
        directory = cls.objects.create(
            name='/',  # 该目录的名字
            owner=user,
            parent=None,
            path=''  # 根目录为空字符，方便后续 URL 拼接不出现 // 影响美观  （不包括跟路由目录的路径）
        )
        return directory

    def get_url(self):  # url格式
        return '/index/{}/{}'.format(self.owner.name, self.path.replace("/","_=_")) #url不允许出现“/”

    def rmdir(self):
        """
            删除子目录和子目录下的文件，以及自身包含的文件和自身
        """
        for subdir in Directory.objects.filter(parent=self):
            for file in subdir.file_set.all():
                Link.minus_one(file)

        for file in self.file_set.all():
            Link.minus_one(file)
        # 从数据库中删除
        self.delete()


class File(models.Model):
    """
        todo:创建相同文件夹后保存文件会报错
        name:   用户能看到的文件目录名.
                考虑到文件名只是存在于数据库的字段，所以不需要限制命名规则
        digest: 文件的 sha1 摘要，也是文件真正的名字      （在这里面digest和path进行对应）
        owner:  （外键）文件所有者 user的id
        share:  是否共享
        size:   文件大小
        parent: （外键）上级目录  directory目录的id号
        path:   相对路径，包含了 digest 作为文件名，和用户自定义的树形结构对应
                但是服务器的储存不按照这个结构存放
                如果对应的话，那么多个File对象映射同一个文件时，下载路径按照 path 来会出错
                此外，path 需要包含用户的根目录，如 user_12，否则用户无法引用到其他用户的文件
                文件的 path 不应该包括文件名，否则会造成改 name 时 path 不能一起改
                保存格式为 子目录\子目录  （不包含用户名的目录）
        app_path:该总用例需要跑的APP
        email_data:该文件关联的邮箱，也就是该文件需要发送到哪些邮箱
    """

    name = models.CharField(max_length=256)
    owner = models.ForeignKey(User, on_delete=models.CASCADE)
    size = models.IntegerField(default=0)
    parent = models.ForeignKey(Directory, on_delete=models.CASCADE)
    digest = models.CharField(max_length=40)
    path = models.CharField(max_length=4096, default='')
    datetime = models.DateTimeField(auto_now_add=True)
    app_path=models.CharField(max_length=256,null=True)
    email_data=models.ManyToManyField(Email,verbose_name="该文件需要关联的邮箱")
    progress_bar=models.FloatField(default=float(0), null=True,verbose_name="进度条事项")
    # run_frequency=models.CharField()

    # share = models.IntegerField()  # 1为共享  0为不共享

    def __str__(self):
        return self.name

    def get_full_path_file(self):
        return os.path.join(get_media_abspath(), self.digest,self.name)

    def get_full_path(self):
        """ 文件的服务器路径 """
        # todo:（文件夹横杠问题）
        return os.path.join(get_media_abspath(), self.digest)

    def remove_from_disk(self):
        """
            删除磁盘上的文件，而不是只减少计数器+删除 File 对象
            用于发现重复文件后，清除新添加的文件，保留用户的 File 对象，改写其 path 值
            todo:实际发现 重复文件并没有删除  到时候需要重写方法  原因是self.get_full_path()获取的是文件夹路径而不是文件路径！！！！
        """
        import shutil
        shutil.rmtree(self.get_full_path())
    def get_url(self):
        """
            没有这步判断，根目录下的文件链接会多一条杠。
            这是打开文件时候URL的路径！！！
        """
        if self.path:
            # 不是在某个目录下 12.17 _=_为url样式
            return '/index/{}/{}_=_{}'.format(self.owner.name, self.path.replace("/","_=_"), self.name) #url不允许出现“/”
        else:
            # 在某个目录下
            return '/index/{}/{}'.format(self.owner.name, self.name)

    def get_size(self):  # Byte
        """
            格式转换模式，尽量贴合人的习惯
        """
        size = self.size
        if size > 1024 ** 3:  # GB
            size = '{:.2f} GB'.format(size / (1024 ** 3))
        elif size > 1024 ** 2:  # MG
            size = '{:.2f} MB'.format(size / (1024 ** 2))
        elif size > 1024:
            size = '{:.2f} KB'.format(size / (1024))
        else:
            size = '{:.2f} Bytes'.format(size)
        return size

    ######
    #进度条相关操作
    #######
    def init_progress_bar_value(self):
        self.progress_bar=float(0)
        self.save()

    def set_progress_bar_value(self,value):
        self.progress_bar=value
        self.save()

    def get_progress_bar_value(self):
        return self.progress_bar

    #
    # def delete_progress_bar_value(self):
    #     return


class Link(models.Model):
    """
        记录文件的摘要和links数
        当用户删除文件时，删掉文件对象，但是不从磁盘删除，
        除非对应的 link 数为0，表示该 hash 值对应的所有文件已经删光，
        此时，从磁盘删除文件

        每次上传文件必然产生两种情况：
            1. 产生一个新的 link 对象（该服务器上没有相关文件时）
            2. links 值 + 1 （该服务器有相关文件时）

        之前把 links 属性放在 File，有一个问题，当记录 links 的文件被删除时，
        这个值就丢失了
    """
    digest = models.CharField(max_length=40, primary_key=True)  # 和 digest 绑定，而不是和文件绑定
    links = models.IntegerField()  # links 数

    def __str__(self):
        return str(self.links)

    @classmethod
    def add_one(cls, file):
        """
            新增文件后调用。使得计数器加一
            如果对应的 digest 没有计数器，则创建计数器，并 links = 1
        """
        nums = File.objects.filter(digest=file.digest).count()
        link_objects = cls.objects.filter(digest=file.digest)
        if link_objects:
            link = link_objects[0]
            link.links = nums
            link.save()
        else:
            link = cls.objects.create(digest=file.digest, links=nums)  # nums 为1

    @classmethod
    def minus_one(cls, file):
        """
            删除文件后调用。使得计数器减一
            如果对应的 digest 的计数器为 0，那么从磁盘删除掉这个文件
        """
        link = cls.objects.get(digest=file.digest)
        link.links -= 1

        if link.links < 1:

            file.remove_from_disk()
            link.delete()
        else:
            link.save()

        file.delete()


